/**
 * README
 * 
 * Modificacion de la biblioteca jWave disponible en http://code.google.com/p/jwave/
 * Convertidos los tipos de datos a float para agilizar el tratamiendo de grandes arrays de datos
 * como son los que se tratan en analisis genomicos.
 * Los autores originales de las funciones y del código de la biblioteca cuando fue seleccionada en
 * Abril de 2012 eran:
 *        Christian Scheiblich
 *        Thomas Leduc
 *        sashi
 *        Pol Kennel
 *        Thomas Haider
 *        
 * Por supuesto, todo el merito, honores y demas menciones sobre esta adaptacion les corresponden a ellos
 * y nada mas que a ellos.
 * 
 * 
 * This is a modified version of jWave, available in http://code.google.com/p/jwave/
 * It has been replace the double datatype with float for performance reasons in very big arrays used in
 * bioinformatics like genomic analysis.
 * Original authors of functions and the library when it has been selected in 2012's April were:
 *        Christian Scheiblich
 *        Thomas Leduc
 *        sashi
 *        Pol Kennel
 *        Thomas Haider
 *        
 * Of course, all the merits and mentions about this adaptation have corresponded to them.
 * 
 */

package ev.maths.handlers;

import ev.maths.Complex;

/**
 * Clase básica para transformaciones como Fast Fourier Transform (FFT), Fast
 * Wavelet Transform (FWT), Fast Wavelet Packet Transform (WPT), o Discrete
 * Wavelet Transform (DWT).
 * 
 * @date 01.08.2012
 * @author Enrique Vázquez de Luis
 */
public abstract class BasicTransform implements TransformInterface {

  /**
   * Constructor
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   */
  protected BasicTransform( ) {
  } // BasicTransform

  /**
   * Realiza la transformada de una función
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param arrTime Coeficientes en el dominio del tiempo
   * @return Coeficientes en el dominio de Hilbert
   */
  public abstract float[ ] forward( float[ ] arrTime );

  /**
   * Realiza la transformada inversa de una función en el dominio de la frecuencia
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param arrFreq Coeficientes en el dominio de Hilbert
   * @return Coeficientes en el dominio del tiempo
   */
  public abstract float[ ] reverse( float[ ] arrFreq );

  /**
   * Realiza la transformada de una función compleja
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param arrTime Coeficientes en el dominio del tiempo
   * @return Coeficientes en el dominio de Hilbert
   */
  public Complex[ ] forward( Complex[ ] arrTime ) {
    return null;
  } // forward

  /**
   * Realiza la transformada inversa de una función compleja
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param arrFreq Coeficientes en el dominio de Hilbert
   * @return Coeficientes en el dominio del tiempo
   */
  public Complex[ ] reverse( Complex[ ] arrFreq ) {
    return null;
  } // reverse


  /**
   * Realiza la transformada bidimensional de una funcion
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param matTime Coeficientes en el dominio del tiempo
   * @return Coeficientes en el dominio de la fecuencia
   */
  public float[ ][ ] forward( float[ ][ ] matTime ) {

    int noOfRows = matTime.length;
    int noOfCols = matTime[ 0 ].length;

    float[ ][ ] matHilb = new float[ noOfRows ][ noOfCols ];

    for( int i = 0; i < noOfRows; i++ ) {

      float[ ] arrTime = new float[ noOfCols ];

      for( int j = 0; j < noOfCols; j++ )
        arrTime[ j ] = matTime[ i ][ j ];

      float[ ] arrHilb = forward( arrTime );

      for( int j = 0; j < noOfCols; j++ )
        matHilb[ i ][ j ] = arrHilb[ j ];

    } // rows

    for( int j = 0; j < noOfCols; j++ ) {

      float[ ] arrTime = new float[ noOfRows ];

      for( int i = 0; i < noOfRows; i++ )
        arrTime[ i ] = matHilb[ i ][ j ];

      float[ ] arrHilb = forward( arrTime );

      for( int i = 0; i < noOfRows; i++ )
        matHilb[ i ][ j ] = arrHilb[ i ];

    } // cols

    return matHilb;
  } // forward

  /**
   * Realiza la transformada inversa bidimensional
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param matFreq Coeficientes en el dominio del tiempo
   * @return Coeficientes en el dominio de la fecuencia
   */
  public float[ ][ ] reverse( float[ ][ ] matFreq ) {

    int noOfRows = matFreq.length;
    int noOfCols = matFreq[ 0 ].length;

    float[ ][ ] matTime = new float[ noOfRows ][ noOfCols ];

    for( int j = 0; j < noOfCols; j++ ) {

      float[ ] arrFreq = new float[ noOfRows ];

      for( int i = 0; i < noOfRows; i++ )
        arrFreq[ i ] = matFreq[ i ][ j ];

      float[ ] arrTime = reverse( arrFreq ); // AED 

      for( int i = 0; i < noOfRows; i++ )
        matTime[ i ][ j ] = arrTime[ i ];

    } // cols

    for( int i = 0; i < noOfRows; i++ ) {

      float[ ] arrFreq = new float[ noOfCols ];

      for( int j = 0; j < noOfCols; j++ )
        arrFreq[ j ] = matTime[ i ][ j ];

      float[ ] arrTime = reverse( arrFreq ); // AED 

      for( int j = 0; j < noOfCols; j++ )
        matTime[ i ][ j ] = arrTime[ j ];

    } // rows

    return matTime;
  } // reverse

  /**
   * Realiza la transformada tridimensional
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param spcTime Coeficientes en el dominio del tiempo
   * @return Coeficientes en el dominio de la fecuencia
   */
  public float[ ][ ][ ] forward( float[ ][ ][ ] spcTime ) {

    int noOfRows = spcTime.length; // first dimension
    int noOfCols = spcTime[ 0 ].length; // second dimension
    int noOfHigh = spcTime[ 0 ][ 0 ].length; // third dimension

    float[ ][ ][ ] spcHilb = new float[ noOfRows ][ noOfCols ][ noOfHigh ];

    for( int i = 0; i < noOfRows; i++ ) {

      float[ ][ ] matTime = new float[ noOfCols ][ noOfHigh ];

      for( int j = 0; j < noOfCols; j++ ) {

        for( int k = 0; k < noOfHigh; k++ ) {

          matTime[ j ][ k ] = spcTime[ i ][ j ][ k ];

        } // high

      } // cols      

      float[ ][ ] matHilb = forward( matTime ); // 2-D forward

      for( int j = 0; j < noOfCols; j++ ) {

        for( int k = 0; k < noOfHigh; k++ ) {

          spcHilb[ i ][ j ][ k ] = matHilb[ j ][ k ];

        } // high

      } // cols

    } // rows  

    for( int j = 0; j < noOfCols; j++ ) {

      for( int k = 0; k < noOfHigh; k++ ) {

        float[ ] arrTime = new float[ noOfRows ];

        for( int i = 0; i < noOfRows; i++ )
          arrTime[ i ] = spcHilb[ i ][ j ][ k ];

        float[ ] arrHilb = forward( arrTime ); // 1-D forward

        for( int i = 0; i < noOfRows; i++ )
          spcHilb[ i ][ j ][ k ] = arrHilb[ i ];

      } // high

    } // cols

    return spcHilb;

  } // forward

  /**
   * Realiza la transformada inversa tridimensional.
   * 
   * @date 01.08.2012
   * @author Enrique Vázquez de Luis
   * @param spcHil Coeficientes en el dominio del tiempo
   * @return Coeficientes en el dominio de la fecuencia
   */
  public float[ ][ ][ ] reverse( float[ ][ ][ ] spcHilb ) {

    int noOfRows = spcHilb.length; 
    int noOfCols = spcHilb[ 0 ].length; 
    int noOfHigh = spcHilb[ 0 ][ 0 ].length; 

    float[ ][ ][ ] spcTime = new float[ noOfRows ][ noOfCols ][ noOfHigh ];

    for( int i = 0; i < noOfRows; i++ ) {

      float[ ][ ] matHilb = new float[ noOfCols ][ noOfHigh ];

      for( int j = 0; j < noOfCols; j++ ) {

        for( int k = 0; k < noOfHigh; k++ ) {

          matHilb[ j ][ k ] = spcHilb[ i ][ j ][ k ];

        } // high

      } // cols      

      float[ ][ ] matTime = reverse( matHilb ); // 2-D reverse

      for( int j = 0; j < noOfCols; j++ ) {

        for( int k = 0; k < noOfHigh; k++ ) {

          spcTime[ i ][ j ][ k ] = matTime[ j ][ k ];

        } // high

      } // cols

    } // rows  

    for( int j = 0; j < noOfCols; j++ ) {

      for( int k = 0; k < noOfHigh; k++ ) {

        float[ ] arrHilb = new float[ noOfRows ];

        for( int i = 0; i < noOfRows; i++ )
          arrHilb[ i ] = spcTime[ i ][ j ][ k ];

        float[ ] arrTime = reverse( arrHilb ); // 1-D reverse

        for( int i = 0; i < noOfRows; i++ )
          spcTime[ i ][ j ][ k ] = arrTime[ i ];

      } // high

    } // cols

    return spcTime;

  } // reverse


} // class
